import axios from 'axios'
import {ElNotification, ElMessageBox, ElMessage, ElLoading} from 'element-plus'
import {getToken} from '@/utils/auth'
import errorCode from '@/utils/errorCode'
import {tansParams, blobValidate} from '@/utils/xpp'
import cache from '@/plugins/cache'
import {saveAs} from 'file-saver'
import lodash from 'lodash'
import * as ExcelJs from "exceljs";
import {isVoid, isNotVoid} from "@/utils/util";
import useUserStore from '@/store/modules/user'

let downloadLoadingInstance;
// 是否显示重新登录
export let isRelogin = {show: false};

axios.defaults.headers['Content-Type'] = 'application/json;charset=utf-8'
// 创建axios实例
const service = axios.create({
    // axios中请求配置有baseURL选项，表示请求URL公共部分
    baseURL: import.meta.env.VITE_APP_BASE_API,
    // 超时
    timeout: 1200000
})

// request拦截器
service.interceptors.request.use(config => {
    // 是否需要设置 token
    const isToken = (config.headers || {}).isToken === false
    // 是否需要防止数据重复提交
    const isRepeatSubmit = (config.headers || {}).repeatSubmit === false
    if (getToken() && !isToken) {
        config.headers['Authorization'] = 'Bearer ' + getToken() // 让每个请求携带自定义token 请根据实际情况自行修改
    }
    // get请求映射params参数
    if (config.method === 'get' && config.params) {
        let url = config.url + '?' + tansParams(config.params);
        url = url.slice(0, -1);
        config.params = {};
        config.url = url;
    }
    if (!isRepeatSubmit && (config.method === 'post' || config.method === 'put')) {
        const requestObj = {
            url: config.url,
            data: typeof config.data === 'object' ? JSON.stringify(config.data) : config.data,
            time: new Date().getTime()
        }
        const sessionObj = cache.session.getJSON('sessionObj')
        if (sessionObj === undefined || sessionObj === null || sessionObj === '') {
            cache.session.setJSON('sessionObj', requestObj)
        } else {
            const s_url = sessionObj.url;                // 请求地址
            const s_data = sessionObj.data;              // 请求数据
            const s_time = sessionObj.time;              // 请求时间
            const interval = 1000;                       // 间隔时间(ms)，小于此时间视为重复提交
            if (s_data === requestObj.data && requestObj.time - s_time < interval && s_url === requestObj.url && !requestObj.url.startsWith("otcOption")) {
                const message = '数据正在处理，请勿重复提交';
                console.warn(`[${s_url}]: ` + message + ":" + s_url)
                return Promise.reject(new Error(message))
            } else {
                cache.session.setJSON('sessionObj', requestObj)
            }
        }
    }
    return config
}, error => {
    console.log(error)
    Promise.reject(error)
})

// 响应拦截器
service.interceptors.response.use(res => {
        // 未设置状态码则默认成功状态
        const code = res.data.code || 200;
        // 获取错误信息
        let msg = errorCode[code] || res.data.msg || errorCode['default']
        if(isNotVoid(res.data.msg)){
              msg = res.data.msg;
        }

        // 二进制数据则直接返回
        if (res.request.responseType === 'blob' || res.request.responseType === 'arraybuffer') {
            return res
        }
        if (code === 401) {
            if (!isRelogin.show) {
                isRelogin.show = true;
                ElMessageBox.confirm('登录状态已过期，您可以继续留在该页面，或者重新登录', '系统提示', {
                        confirmButtonText: '重新登录',
                        cancelButtonText: '取消',
                        type: 'warning'
                    }
                ).then(() => {
                    isRelogin.show = false;
                    // useUserStore().logOut().then(() => {
                    //   location.href = '/index';
                    // })
                }).catch(() => {
                    isRelogin.show = false;
                });
            }
            return Promise.reject('无效的会话，或者会话已过期，请重新登录。')
        } else if (code === 500) {
            /*ElMessage({
                message: msg,
                type: 'error'
            })*/
            return Promise.reject(res.data)
        } else if (code === 200) {
            return Promise.resolve(res.data)
        } else {
            ElNotification.error({
                title: '{code:' + code + ',msg:' + msg + "}"
            })
            return Promise.reject(res.data)
        }
    },
    error => {
        console.log('err' + error)
        let {message} = error;
        if (message == "Network Error") {
            message = "测试平台后端接口连接异常";
        } else if (message.includes("timeout")) {
            message = "测试平台后端接口请求超时";
        } else if (message.includes("Request failed with status code")) {
            message = "测试平台后端接口" + message.substr(message.length - 3) + "异常";
        }
        ElMessage({
            message: message,
            type: 'error',
            duration: 5 * 1000
        })
        return Promise.reject(error)
    }
)

// 通用下载方法
export function download(url, params, filename) {
    downloadLoadingInstance = ElLoading.service({text: "正在下载数据，请稍候", background: "rgba(0, 0, 0, 0.7)",})
    return service.post(url, params, {
        transformRequest: [(params) => {
            return tansParams(params)
        }],
        headers: {'Content-Type': 'application/x-www-form-urlencoded'},
        responseType: 'blob'
    }).then(async (res) => {
        let data = res.data

        // 若前台不传filename 可以从后台流里面取出文件名
        // let wName = (res?.headers["content-disposition"]+'').match(/filename=(\S+)/)[1]
        const isLogin = await blobValidate(data);
        if (isLogin) {
            const blob = new Blob([data])
            if (!filename) filename = (window.decodeURIComponent((res?.headers["content-disposition"] + '').split('filename=')[1]))
            saveAs(blob, filename)
            ElMessage.success('导出文件成功！');
        } else {
            const resText = await data.text();
            const rspObj = JSON.parse(resText);
            const errMsg = errorCode[rspObj.code] || rspObj.msg || errorCode['default']
            ElMessage.error(errMsg);
        }
        downloadLoadingInstance.close();
    }).catch((r) => {
        ElMessage.error('下载文件出现错误，请联系管理员！')
        downloadLoadingInstance.close();
    })
}

/**
 * 通过前端导出单个sheet页的Excel,数据条数指定 botao.yu
 * @param columnArray 列熟悉设置 例
 * { header: '已实现收益率(%)', key: 'realizedYield', , width: 20 ,columAlign:'right',fmtType:'percent'},
 * fmtType :0:不格式化 1:数据字典 2:数字 3:金额 4:百分比 其实为dict时要指定dictType
 * @param resultList 结果集
 * @param title 导出文件名
 * @param  导出文件名
 */
export function exportExcelByWeb(columnArray, resultList, title) {
    exportExcelSumByWeb(columnArray, resultList, title, '0');
}

/**
 * 通过前端导出单个sheet页的Excel,数据条数指定 botao.yu
 * @param columnArray 列熟悉设置 例
 * { header: '已实现收益率(%)', key: 'realizedYield', , width: 20 ,columAlign:'right',fmtType:'percent'},
 * fmtType :0:不格式化 1:数据字典 2:数字 3:金额 4:百分比 其实为dict时要指定dictType
 * @param resultList 结果集
 * @param title 导出文件名
 * @param sumType 合计类型 0-不合计 1-求和 2-平均值 3。。。
 */
export function exportExcelSumByWeb(columnArray, resultList, title, sumType) {
    let columnObject = {};
    let resultListObect = {};
    let sheetsObject = {};
    let sumTypeObject = {};
    columnObject[title] = columnArray;
    resultListObect[title] = resultList;
    sheetsObject[title] = title;
    sumTypeObject[title] = sumType;
    exportExcelAllSheetSumByWeb(columnObject, resultListObect, sheetsObject, title, sumTypeObject);
}

/**
 * 通过前端导出Excel,数据条数指定 botao.yu
 * @param columnObject 列熟悉设置 例
 * {bizsum:[{ header: '已实现收益率(%)', key: 'realizedYield', , width: 20 ,columAlign:'right',fmtType:'percent'}]},
 * fmtType :0:不格式化 1:数据字典 2:数字 3:金额 4:百分比 其实为dict时要指定dictType
 * @param resultListObect 结果集对象 例如 {bizsum:[bizsum对应的数据结果集]}
 * @param sheetsObject 多sheet对象 例如 {bizsum:"业务概况"}
 * @param title 导出文件名
 */
export function exportExcelAllSheetByWeb(columnObject, resultListObect, sheetsObject, title) {
    let sumTypeObject = {};
    lodash.forEach(sheetsObject, function (value, key) {
        sumTypeObject[key] = '0';
    });
    exportExcelAllSheetSumByWeb(columnObject, resultListObect, sheetsObject, title, sumTypeObject);
}

/**
 * 通过前端导出Excel,数据条数指定 botao.yu
 * @param columnObject 列熟悉设置 例
 * {bizsum:[{ header: '已实现收益率(%)', key: 'realizedYield', , width: 20 ,columAlign:'right',fmtType:'percent'，sumFlag：'1'}]},
 * fmtType :0:不格式化 1:数据字典 2:数字 3:金额 4:百分比 其实为dict时要指定dictType
 * @param resultListObect 结果集对象 例如 {bizsum:[bizsum对应的数据结果集]}
 * @param sheetsObject 多sheet对象 例如 {bizsum:"业务概况"}
 * @param title 导出文件名
 * @param sumTypeObject 合计类型 0-不合计 1-求和 2-平均值 3。。。 需要合计时，列中也要有sumFlag=1才会合计
 */
export function exportExcelAllSheetSumByWeb(columnObject, resultListObect, sheetsObject, title, sumTypeObject) {
    const workbook = new ExcelJs.Workbook();
    lodash.forEach(sheetsObject, function (value, key) {
        const worksheet = workbook.addWorksheet(value);
        //设置列
        worksheet.columns = columnObject[key];
        //填充数据
        let expRows = lodash.cloneDeep(resultListObect[key]);
        let columnArray = lodash.cloneDeep(columnObject[key]);
        let sumType = sumTypeObject[key];
        let sumRow = {};
        worksheet.addRows(expRows);
        //设置列头样式和列属性
        for (let j = 1; j <= columnArray.length; j++) {
            //列头背景色
            worksheet.getRow(1).getCell(j).fill = {
                type: 'pattern',
                pattern: 'lightGrid',
                bgColor: {argb: '8e8a8a'},
                fgColor: {argb: '8e8a8a'}
            };
            //列排列属性设置 只设置一次
            worksheet.getColumn(j).alignment = {vertical: 'middle', horizontal: columnArray[j - 1].columAlign};
            //列头居中
            worksheet.getRow(1).getCell(j).alignment = {vertical: 'middle', horizontal: 'center'};
            //数据格式化
            if (isNotVoid(columnArray[j - 1].fmtType) && columnArray[j - 1].fmtType == '2') {
                //数字格式化
                worksheet.getColumn(columnArray[j - 1].columKey).numFmt = '###0.00;\-###0.00';
            } else if (isNotVoid(columnArray[j - 1].fmtType) && columnArray[j - 1].fmtType == '3') {
                //百分比格式化
                worksheet.getColumn(columnArray[j - 1].columKey).numFmt = '#,##0.00;\-#,##0.00';
            } else if (isNotVoid(columnArray[j - 1].fmtType) && columnArray[j - 1].fmtType == '4') {
                //百分比格式化
                worksheet.getColumn(columnArray[j - 1].columKey).numFmt = '0.00%';
            } else if (isNotVoid(columnArray[j - 1].fmtType) && columnArray[j - 1].fmtType == '1' && isNotVoid(columnArray[j - 1].dictType)) {
                //数据字典格式化
                let tmpDict = columnArray[j - 1].dictType;
                let tmpDictObj = {};
                if (isNotVoid(tmpDict)) {
                    lodash.forEach(expRows, obj => {
                        tmpDictObj = lodash.find(tmpDict, function (o) {
                            return o.dictValue == '' + obj[columnArray[j - 1].columKey]
                        });
                        obj[columnArray[j - 1].columKey] = (isNotVoid(tmpDictObj) && isNotVoid(tmpDictObj.dictLabel)) ? tmpDictObj.dictLabel : "";
                    })
                }
            }
            let sumVal = 0;
            //如果有合计
            if (isNotVoid(sumType) && sumType == '1' && columnArray[j - 1].sumFlag == '1') {
                //合计
                lodash.forEach(expRows, obj => {
                    sumVal += obj[columnArray[j - 1].columKey];
                })
                sumRow[columnArray[j - 1].columKey] = sumVal;
            } else if (isNotVoid(sumType) && sumType == '2' && columnArray[j - 1].sumFlag == '1') {
                //平均值
                lodash.forEach(expRows, obj => {
                    sumVal += obj[columnArray[j - 1].columKey];
                })
                sumVal = sumVal / expRows.length;
                sumRow[columnArray[j - 1].columKey] = sumVal;
            }
        }
        if (isNotVoid(sumType) && sumType == '1' && resultListObect[key].length > 0) {
            expRows.push(sumRow);
            worksheet.addRow(sumRow);
        }
        //添加边框线
        for (let i = 1; i <= expRows.length; i++) {
            for (let j = 1; j <= columnArray.length; j++) {
                worksheet.getRow(i).getCell(j).border = {
                    top: {style: 'thin'},
                    left: {style: 'thin'},
                    bottom: {style: 'thin'},
                    right: {style: 'thin'}
                };
            }
            //行数据覆盖
            worksheet.getRow(i + 1).values = expRows[i - 1];
        }

        //最后一行数据加边框  数据渲染完后才能getRow,所以放在最后
        for (let j = 1; j <= columnArray.length; j++) {
            worksheet.getRow(expRows.length + 1).getCell(j).border = {
                top: {style: 'thin'},
                left: {style: 'thin'},
                bottom: {style: 'thin'},
                right: {style: 'thin'}
            };
            if (isNotVoid(sumType) && sumType == '1' && resultListObect[key].length > 0) {
                //如果有合计并且有数据，最后一行样式调整为黄色背景
                worksheet.getRow(expRows.length + 1).getCell(j).fill = {
                    type: 'pattern',
                    pattern: 'lightGrid',
                    bgColor: {argb: 'f5f27e'},
                    fgColor: {argb: 'f5f27e'}
                };
                worksheet.getRow(expRows.length + 1).getCell(j).font = {color: {argb: 'fa0429'}, bold: true}
            }
        }
    })

    workbook.xlsx.writeBuffer()
        .then(buffer => {
            ElMessage.success('导出文件成功！');
            saveAs(new Blob([buffer]), title + `${Date.now()}.xlsx`)
        })
        .catch(err =>
            ElMessage.error('导出Excel出错', err)
        );

}

export default service
